package com.hyk.service.impl;

import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.RandomUtil;
import com.alicp.jetcache.Cache;
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.anno.CreateCache;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hyk.domain.CashRecharge;
import com.hyk.domain.CashRechargeAuditRecord;
import com.hyk.domain.Coin;
import com.hyk.dto.AdminBankDto;
import com.hyk.dto.AdminUserDto;
import com.hyk.dto.UserDto;
import com.hyk.enums.AccountEnums;
import com.hyk.fegin.AdminBankFegin;
import com.hyk.fegin.AdminUserFegin;
import com.hyk.feign.UserServiceFeign;
import com.hyk.mapper.CashRechargeMapper;
import com.hyk.model.CoinModel;
import com.hyk.service.AccountService;
import com.hyk.service.CashRechargeAuditRecordService;
import com.hyk.service.CashRechargeService;
import com.hyk.service.CoinService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
public class CashRechargeServiceImpl extends ServiceImpl<CashRechargeMapper, CashRecharge> implements CashRechargeService{

    @Autowired
    private UserServiceFeign userServiceFeign;

    @Resource
    private CashRechargeMapper cashRechargeMapper;

    private final Snowflake snowflake = new Snowflake(2,1);


    @CreateCache(name = "CASH_RECHARGE_LOCK:", expire = 100, timeUnit = TimeUnit.SECONDS, cacheType = CacheType.BOTH)
    private Cache<String, String> cache;


    @Resource
    private AdminUserFegin adminUserFegin;

    @Autowired
    private CoinService coinService;

    @Autowired
    private AccountService accountService;

    @Autowired
    private AdminBankFegin adminBankFegin;

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Autowired
    private CashRechargeAuditRecordService cashRechargeAuditRecordService;

    @Override
    public Page<CashRecharge> findByPage(Page<CashRecharge> page,
                                         Long coinId,
                                         Long userId,
                                         String userName,
                                         String mobile,
                                         Byte status,
                                         String numMin,
                                         String numMax,
                                         String startTime,
                                         String endTime) {
        List<Long> searchIds = new ArrayList<>();
        Map<Long,UserDto> user = new HashMap<>();
        if(userId!=null ||
           StringUtils.isNotBlank(userName) ||
           StringUtils.isNotBlank(mobile)){
            List<Long> ids = new ArrayList<>();
            if (userId!=null){
                ids.add(userId);
            }
            user = userServiceFeign.getBasicUsers(ids.size() == 0 ? null : ids, mobile, userName);
            Set<Map.Entry<Long,UserDto>> entries = user.entrySet();
            for (Map.Entry<Long,UserDto> map:entries) {
                searchIds.add(map.getKey());
            }
            if (CollectionUtils.isEmpty(searchIds)) {
                return page;
            }
        }

        Page<CashRecharge> rechargePage = cashRechargeMapper.findByPage(page,coinId,searchIds,status,numMin,numMax,startTime,endTime);

        List<CashRecharge> records = rechargePage.getRecords();
        if(CollectionUtils.isEmpty(records)){
            return rechargePage;
        }
        if(CollectionUtils.isEmpty(searchIds)){

            Set<Long> responseIds = records.stream().map(CashRecharge::getUserId).collect(Collectors.toSet());
            ArrayList<Long> longs = new ArrayList<>(responseIds);
            user = userServiceFeign.getBasicUsers(longs.size() == 0 ? null : longs,mobile,userName);
        }
        buildCashRecharge(user,records);
        return rechargePage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void checkRecharge(CashRecharge cashRecharge) {

        cache.tryLockAndRun(cashRecharge.getId() + "",300,TimeUnit.SECONDS,()->{
//            try{
//                Thread.sleep(50000);
//            }catch (InterruptedException e){
//                e.printStackTrace();
//            }
            if (cashRecharge.getStatus() == 1){
                //修改原有数据，添加订单完成时间
                CashRecharge cashRecharge1 = getById(cashRecharge);
                if (cashRecharge1 == null){
                    throw new IllegalArgumentException("订单数据错误");
                }
                cashRecharge1.setLastTime(new Date());
                cashRecharge1.setLastUpdateTime(new Date());
                cashRecharge1.setStatus(cashRecharge.getStatus());
                cashRecharge1.setAuditRemark(cashRecharge.getRemark());
                updateById(cashRecharge1);

                //给账户增加余额
                QueryWrapper<Coin> wrapper = new QueryWrapper<>();
                wrapper.eq("name","CNY");
                List<Coin> list = coinService.list(wrapper);
                if (CollectionUtils.isEmpty(list)){
                    throw new IllegalArgumentException("CNY未配置");
                }

                //添加资金流水
                accountService.transfer(list.get(0).getId(),cashRecharge1.getCoinId(),null,cashRecharge1.getUserId(),cashRecharge1.getId(), AccountEnums.recharge_into.getCode(),cashRecharge1.getNum(),cashRecharge1.getFee(),cashRecharge1.getRemark());

                //充值流水
                CashRechargeAuditRecord cashRechargeAuditRecord = new CashRechargeAuditRecord();
                cashRechargeAuditRecord.setOrderId(cashRecharge1.getId());
                Long userId = Long.parseLong(SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
                cashRechargeAuditRecord.setAuditUserId(userId);
                Map<Long, AdminUserDto> adminUser = adminUserFegin.getAdminUser(Arrays.asList(userId));
                AdminUserDto userDto = adminUser.get(userId);
                cashRechargeAuditRecord.setAuditUserName(userDto.getUsername());
                cashRechargeAuditRecord.setCreated(new Date());
                cashRechargeAuditRecord.setId(snowflake.nextId());
                cashRechargeAuditRecord.setRemark(cashRecharge.getRemark());
                cashRechargeAuditRecord.setStep((byte)(cashRecharge1.getStep()+(byte)1));
                cashRechargeAuditRecord.setStatus((byte)1);
                cashRechargeAuditRecordService.save(cashRechargeAuditRecord);
            }else{
                saveCashRecgarge(cashRecharge);
            }
        });

    }

    @Override
    public CashRecharge buy(CoinModel coinModel) {

        //填写充值记录
        CashRecharge cashRecharge = new CashRecharge();
        cashRecharge.setStatus((byte)0);

        AdminBankDto adminBankDto = adminBankFegin.getAdminUser();
        cashRecharge.setBankCard(adminBankDto.getBankCard());
        cashRecharge.setBankName(adminBankDto.getBankName());
        cashRecharge.setName(adminBankDto.getName());
        cashRecharge.setCoinId(Long.parseLong(coinModel.getCoinId()));
        Coin byId = coinService.getById(coinModel.getCoinId());
        cashRecharge.setCoinName(byId.getName());
        cashRecharge.setFee(BigDecimal.ZERO);
        cashRecharge.setFeecoin(coinModel.getCoinId());

        //计算手续费
        Object buyObject = redisTemplate.opsForHash().get("CNY","CNY2USDT");
        if (buyObject == null){
            throw new IllegalArgumentException("请设置人民币充值GCN换算费率");
        }
        cashRecharge.setMum(new BigDecimal(coinModel.getNum()).multiply(new BigDecimal(buyObject.toString())));
        cashRecharge.setNum(new BigDecimal(coinModel.getNum()));
        Long userId = Long.parseLong(SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString());
        cashRecharge.setUserId(userId);
        cashRecharge.setType("bank");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        String format = sdf.format(new Date());
        format = format + System.currentTimeMillis()+ RandomUtil.randomNumbers(4);
        cashRecharge.setTradeno(format);
        cashRecharge.setRemark(RandomUtil.randomNumbers(6));
        cashRecharge.setCreated(new Date());
        cashRecharge.setLastUpdateTime(new Date());
        cashRecharge.setStep((byte)1);
        save(cashRecharge);

        return cashRecharge;
    }

    private void saveCashRecgarge(CashRecharge cashRecharge) {
        CashRecharge cashRecharge1 = getById(cashRecharge);
        cashRecharge1.setLastUpdateTime(new Date());
        cashRecharge1.setStatus(cashRecharge.getStatus());
        cashRecharge1.setRemark(cashRecharge.getRemark());
        updateById(cashRecharge1);

        CashRechargeAuditRecord cashRechargeAuditRecord = new CashRechargeAuditRecord();
        cashRechargeAuditRecord.setOrderId(cashRecharge1.getId());
        String s = SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString();
        Long userId = Long.parseLong(s);
        cashRechargeAuditRecord.setAuditUserId(userId);
        Map<Long, AdminUserDto> adminUser = adminUserFegin.getAdminUser(Arrays.asList(userId));
        AdminUserDto userDto = adminUser.get(userId);
        cashRechargeAuditRecord.setAuditUserName(userDto.getUsername());
        cashRechargeAuditRecord.setCreated(new Date());
        cashRechargeAuditRecord.setId(snowflake.nextId());
        cashRechargeAuditRecord.setRemark(cashRecharge.getRemark());
        cashRechargeAuditRecord.setStep((byte)1);
        cashRechargeAuditRecord.setStatus((byte)1);
        cashRechargeAuditRecordService.save(cashRechargeAuditRecord);
    }

    private void buildCashRecharge(Map<Long, UserDto> user, List<CashRecharge> records) {
        for(CashRecharge cashRecharge : records){
            UserDto userDto = user.get(cashRecharge.getUserId());
            if(userDto != null){
                cashRecharge.setRealName(userDto.getRealName());
                cashRecharge.setUsername(userDto.getUsername());
                cashRecharge.setMobile(userDto.getMobile());
            }else{
                cashRecharge.setRealName("数据为空");
                cashRecharge.setUsername("数据为空");
                cashRecharge.setMobile("数据为空");
            }
        }
    }
}
